<?PHP
/**
 *
 *   Copyright (C) 2006-2008  Ron Jerome
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License along
 *   with this program; if not, write to the Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 ****************************************************************************/

function biblio_view_node($nid) {
  drupal_goto('node/'.(int)$nid, NULL, NULL, 301); // set a 301 response code
}
/**
 * @return unknown_type
 */
function biblio_db_search() {

  $arg_list = array();
  $arg_list = func_get_args();
  foreach ($_GET as $key => $value) {
    if ($key != 'q') {
      $arg_list[] = check_plain($key);
      $arg_list[] = check_plain($value);
    }
  }


  // Drupal search? It returns an array of search results. We store the nids
  // of the result nodes and make them a "where n.nid in {..}" filter.
  // After installing the filter, we can go on as usual.

  // When called manually, search takes one parameter, i.e.
  // biblio_db_search('search', 'bla blu')
  $search = array_search('search', $arg_list);
  if ($search !== FALSE) {
    $keys = $arg_list[$search+1];

    // Special case: if search is activated via URL, i.e., biblio/search/...,
    // we reset the search session filter. Two searches are not combinable.
    $base =  variable_get('biblio_base', 'biblio');
    if (preg_match('+'.$base.'/search/+', $_GET['q'])) {
      $_SESSION['biblio_filter'] = array();
    }
  }
  else {
    $keys = _get_biblio_search_filter();
  }

  if ($keys) {
    // Only search in biblio nodes. If we use a SESSION filter and have a list of
    // nids stored there, don't re-search. List is reset when submitting a new search.
    if ($search !== FALSE || !_get_biblio_search_filter('nodelist')) {
      if ($result = biblio_build_search_query($keys)) {
        $node_list = '';
        while ($nid = db_result($result)) {
          $node_list .= $nid.",";
        }
        // No node search result. Make sure we find nothing, too. Node -1 does not exist.
        if (empty($node_list)) $node_list = '-1';

        // Store as SESSION filter or argument list.
        // When called as function argument it takes only one parameter, i.e.
        // biblio_db_search('search', 'bla blu') and we must insert the node
        // list inbetween.
        if ($search !== FALSE) {
          array_splice($arg_list, $search + 1, 0, $node_list);
        }
        else {
          $_SESSION['biblio_filter'] = array(array('search', rtrim($node_list, ','), $keys));
        }
      }
      // Wrong query (too short, only negative words etc.). Warning has been issued.
      else $_SESSION['biblio_filter'] = array();
    }
  }

  $inline = in_array('inline', $arg_list);
  $inline = in_array('profile', $arg_list)?'profile':$inline;

  $query_info = biblio_build_query($arg_list);
  if ($query_info['rss']['feed']){
    biblio_filter_feed($query_info['query'], $query_info['query_terms'], $query_info['rss']);
  }
  else{
    //$count = db_result(db_query($query_info['count_query'],$query_info['query_terms']));
    $nodes = array();
    $result = pager_query($query_info['query'], variable_get('biblio_rowsperpage', 25),0,$query_info['count_query'],$query_info['query_terms']);
    $query_info['filter_line'] = _biblio_filter_info_line($query_info['args']);

    while ($res = db_fetch_array($result)) {
      $node = node_load($res['nid']);
      foreach($res as $key => $value) {
        if (!isset($node->$key)) {
          $node->$key = $value;
        }
      }
      $nodes[] = $node;
    }

    return biblio_show_results($nodes, $query_info, $inline);
  }

}
/*
 * biblio_db_search builds the SQL query which will be used to
 * select and order "biblio" type nodes.  The query results are
 * then passed to biblio_show_results for output
 *
 *
 */
function biblio_build_query($arg_list) {
  global $user, $db_type;
  static $bcc; //biblio_contributor (bc) count , increase for every invocation
  static $tcc; //term counter, increase for every invocation
  if ( !isset( $bcc ) ) $bcc = 0;
  if ( !isset( $tcc ) ) $tcc = 0;
  $inline = $rss_info['feed'] = false;
  $joins = array();
  $selects = array();
  $count_selects = array();
  $count_limit = '';

  $selects[] = "DISTINCT(n.nid)";
  $count_selects[] = "DISTINCT(n.nid)";
  //$selects[] = "n.*";
  //$selects[] = "b.*";
  $selects[] = "bt.name as biblio_type_name";

  $joins[] = "left join {biblio} b  on n.vid=b.vid ";
  $joins[] = "inner join {biblio_types} bt  on b.biblio_type=bt.tid ";

  // POSIX regular expression matching, case insensitive
  $match_op = ($db_type == 'pgsql') ? '~*' : 'RLIKE';
   // The following is to be used to compare titles
   // LOWER() is required for case insensitive sorting (at least, in PostgreSQL)
  $sort_title = 'biblio_sort_title';

  $limit = '';
  if (variable_get('biblio_view_only_own', 0) ) {
    $limit .= " AND n.uid = $user->uid ";
  }

  if(array_search('sort', $arg_list) === FALSE) {
    $arg_list[] = 'sort';
    $arg_list[] = variable_get('biblio_sort', 'year');
    $arg_list[] = 'order';
    $arg_list[] = strtolower(variable_get('biblio_order', 'desc'));

  }

  $limits = null;

  if (!isset($_SESSION['biblio_filter']) || !is_array($_SESSION['biblio_filter'])) {
    $_SESSION['biblio_filter'] = array();
  }

  $session = &$_SESSION['biblio_filter'];

  if (!in_array('no_filters', $arg_list)) {
    foreach ($session as $filter) {
      $arg_list = array_merge($arg_list, $filter);
    }
  }

  if (count($arg_list) ) {
    $args = array();
    while ($arg_list) {
      $type = $arg_list[0];
      array_shift($arg_list);
      $operator = ($operator)?$operator:" AND "; //defaults to AND
      switch ($type) {
        case 'no_filters':
          break;
        case 'and':
          $operator = " AND ";
          break;
        case 'or':
          $operator = " OR ";
          break;
        case 'inline':
          $inline = true;
          break;
        case 'rss.xml':
          $rss_info['feed'] = true;
          $count_limit = 'LIMIT '. variable_get('biblio_rss_number_of_entries', 10);
          break;
        case 'profile':
          $inline = "profile";
          break;
        case 'cid':
        case 'aid':
          $bcc++;
          $term = explode("?",array_shift($arg_list));
          $joins[] = "inner join {biblio_contributor} as bc". $bcc ." on n.vid = bc". $bcc .".vid";
          $where[] = "bc". $bcc .".cid = '%d' ";
          $terms[] = db_escape_string($term[0]);
          array_push($args, $type, $term[0]);
          break;
        case 'term':
        case 'term_id':
          $term = explode("?",array_shift($arg_list));
          $joins[] = "inner join {term_node} as tn". $tcc ." on n.vid = tn".$tcc.".vid";
          if ($type == 'term') {
            $joins[] = "inner join  {term_data} as td on tn". $tcc .".tid= td.tid";
            $where[] = "td.name = '%s' ";
          }elseif ($type == 'term_id') {
            $where[] = "tn". $tcc .".tid = '%d' ";
          }
          $terms[] = db_escape_string($term[0]);
          array_push($args, $type, $term[0]);
          $tcc++;
          break;
        case 'tg':
          $term = explode("?",array_shift($arg_list));
          $where[] = "substring($sort_title,1 ,1)" . $match_op . " LOWER('%s')";
          $terms[] = db_escape_string($term[0]);
          array_push($args, $type, $term[0]);
          $operator = NULL;
          break;
        case 'ag': //selects entries whoose authors firstname starts with the letter provided
          $term = explode("?",array_shift($arg_list));
          $where[] = " UPPER(substring(bcd.lastname,1,1)) = '%s' ";
          //$where['bc-rank'] = "bc.rank=0";
          $joins['bc'] = '  INNER JOIN {biblio_contributor} as bc on b.vid = bc.vid ';
          $joins['bcd'] = '  JOIN {biblio_contributor_data} as bcd on bc.cid = bcd.cid ';
          $terms[] = db_escape_string(strtoupper($term[0]));
          array_push($args, $type, $term[0]);
          $operator = NULL;
          break;
        case 'author':
          $bcc++;
          $term = explode("?",array_shift($arg_list));

          if (is_numeric($term[0])){
            $joins[] = "inner join {biblio_contributor} as bc". $bcc ." on n.vid = bc". $bcc .".vid";
            $cids = db_query('SELECT cid FROM {biblio_contributor_data}
                              WHERE cid = %d OR aka = (SELECT aka FROM {biblio_contributor_data} WHERE cid = %d)'
                              ,$term[0], $term[0]);
            while ($cid = db_fetch_object($cids) ){
              $wr .= empty($wr)?'':' OR ';
              $wr .= "bc". $bcc .".cid = $cid->cid ";
            }
            $where[] = (!empty($wr)) ? $wr : "bc". $bcc .".cid = -1 ";
          }else{
            $where[] = " bcd". $bcc .'.name '. $match_op .' "[[:<:]]%s[[:>:]]" ';
            $joins[] = " JOIN {biblio_contributor} as bc". $bcc ." on b.vid = bc". $bcc .".vid ";
            $joins[] = " JOIN {biblio_contributor_data} as bcd". $bcc ." on bc". $bcc .".cid = bcd".$bcc .".cid ";
            $terms[] = db_escape_string($term[0]);
            $operator = NULL;
            $rss_info['title'] = t("Publications by " . $term[0]);
            $rss_info['description'] = t("These publications by %author are part of the works listed at %sitename", array('%author' => $term[0], '%sitename' => variable_get('site_name', 'Drupal')));
            $rss_info['link'] = '/author/' . $term[0];
          }
          array_push($args, $type, $term[0]);
          break;
        case 'publisher':
          $term = explode("?",array_shift($arg_list));
          $where[] = "b.biblio_publisher ". $match_op ." '%s' ";
          $terms[] = db_escape_string($term[0]);
          array_push($args, $type, $term[0]);
          $operator = NULL;
          break;
        case 'year':
          $term = db_escape_string(array_shift($arg_list));
          $where[] = "b.biblio_year=%d ";
          //$limit .= " AND b.biblio_year=%d ";
          $terms[] = (int)$term;
          array_push($args, $type, (int)$term);
          $operator = NULL;
          break;
        case 'uid':
          $term = db_escape_string(array_shift($arg_list));
          $where[] = "n.uid=%d ";
          //$limit .= " AND b.biblio_year=%d ";
          $terms[] = (int)$term;
          array_push($args, $type, (int)$term);
          $operator = NULL;
          break;
        case 'keyword':
          $bkd++;
          $term = explode("?",array_shift($arg_list));
          if (is_numeric($term[0])){
            $terms[] = db_escape_string($term[0]);
            $joins[] = "inner join {biblio_keyword} as bk$bkd on n.vid = bk$bkd.vid";
          //$joins[] = "inner join {biblio_keyword_data} as bkd on bk.kid= bkd.kid";
            $where[] = "bk$bkd.kid = %d ";
          }
          elseif (strlen($term[0]) == 1) {
            $joins['bk'] = '  JOIN {biblio_keyword} as bk on b.vid = bk.vid ';
            $joins['bkd'] = '  LEFT JOIN {biblio_keyword_data} as bkd on bk.kid = bkd.kid ';
            $selects[] = "bkd.word as biblio_keyword";
            $where[] = " UPPER(substring(bkd.word,1,1)) = '%s' ";
            $terms[] = db_escape_string(strtoupper($term[0]));
            //array_push($args, $type, $term[0]);
          }
          else{
            $where[] = " bkd". $bkd .'.word '. $match_op .' "[[:<:]]%s[[:>:]]" ';
            $joins[] = " JOIN {biblio_keyword} as bk". $bkd ." on b.vid = bk". $bkd .".vid ";
            $joins[] = " JOIN {biblio_keyword_data} as bkd". $bkd ." on bk". $bkd .".kid = bkd".$bkd .".kid ";
            $terms[] = db_escape_string($term[0]);
            $operator = NULL;
            $rss_info['title'] = t("Keyword " . $term[0]);
            $rss_info['description'] = t("These publications, containing the keyword: %keyword, are part of the works listed at %sitename", array('%keyword' => $term[0], '%sitename' => variable_get('site_name', 'Drupal')));
            $rss_info['link'] = '/keyword/' . $term[0];
          }
          array_push($args, $type, $term[0]);
          $operator = NULL;
          break;
        case 'citekey':
          $term = explode("?",array_shift($arg_list));
          $terms[] = db_escape_string($term[0]);
          $where[] = "b.biblio_citekey= '%s' ";
          array_push($args, $type, $term[0]);
          $operator = NULL;
          break;
        case 'type':
          $term = db_escape_string(array_shift($arg_list));
          $where[] = "b.biblio_type=%d ";
          //$limit .= $operator. "b.biblio_type=%d ";
          $terms[] = (int)$term;
          array_push($args, $type, (int)$term);
          $operator = NULL;
          break;
        case 'order':
          $term = (db_escape_string(strtolower(array_shift($arg_list))) == 'desc')?'desc':'asc';
          $sort_attrib['order'] = $term;
          break;
        case 'sort':
          $term = db_escape_string(array_shift($arg_list));
          $sort_attrib['sort'] = $term;
          switch ($term) {
            case 'type':
              $sortby = "ORDER BY bt.name %s, $sort_title";
              $selects[] = "bt.name, $sort_title";
              break;
            case 'title':
              $sortby = "ORDER BY $sort_title %s";
              $selects[] = $sort_title;
              break;
            case 'author':
              $sortby = "ORDER BY bcd.lastname %s ";
              $where['bc-rank'] = "bc.rank=0";
              $where['bc-auth-category'] = "bc.auth_category IN (1,5)";
              $joins['bc'] = '  INNER JOIN {biblio_contributor} as bc on b.vid = bc.vid ';
              $joins['bcd'] = '  JOIN {biblio_contributor_data} as bcd on bc.cid = bcd.cid ';
              $selects[] = "bcd.lastname";
              break;
            case 'keyword': // added msh 070808
              $sortby = "ORDER BY bkd.word %s ";
              $joins['bk'] = '  JOIN {biblio_keyword} as bk on b.vid = bk.vid ';
              $joins['bkd'] = '  LEFT JOIN {biblio_keyword_data} as bkd on bk.kid = bkd.kid ';
              $selects[] = "bkd.word as biblio_keyword";
              //$count_selects[] = "bkd.word";
              break;
            case 'year':
            default:
              $sortby = "ORDER BY b.biblio_year %s, b.biblio_date %s, $sort_title %s";
              $selects[] = "b.biblio_year, b.biblio_date";
              $selects[] = $sort_title;
          } //end switch
          break;
        case 'search':
          $term = explode("?",array_shift($arg_list));
              $result_nids = split(',', $term[0]);
              $where[] = "n.nid in (".db_placeholders($result_nids).")";
              foreach ($result_nids as $result_nid) {
                $terms[] = db_escape_string($result_nid);
                array_push($args, $type, $result_nid);
              }
        // Save search keyword to show in the filter list.
              $term = array_shift($arg_list);
              array_push($args, $type, $term);
              $operator = NULL;
              break;
            default:
              $fields = biblio_get_db_fields();
              $term = explode("?",array_shift($arg_list));
              if (in_array("biblio_$type",$fields))
              {
                $where[] = "b.biblio_$type ".$match_op ." '%s' ";
                $terms[] = db_escape_string($term[0]);
                array_push($args, $type, $term[0]);
                $operator = NULL;
              }
              break;
      }
    }
  }
  $where[] = "n.type='biblio' ";
  if ($user->uid != 1 ) {
    $where[] = 'n.status = 1 ';
  }//show only published entries to everyone except admin

  $select = implode(', ', $selects);
  $count_select = implode(', ', $count_selects);
  $join = implode(' ', $joins);

  $where_clause = count($where) > 1 ? '('. implode(') AND (', $where) .')': $where[0];

  $query = db_rewrite_sql("SELECT $select FROM {node} n $join  WHERE $where_clause $limit $sortby $count_limit");
  $count_query = db_rewrite_sql("SELECT COUNT($count_select) FROM {node} n $join  WHERE $where_clause $limit $count_limit");
  $_SESSION['last_biblio_query'] = $query;
  $terms[] = $sort_attrib['order']; // this is either asc or desc to be inserted into the first term of the ORDER clause
  if($sort_attrib['sort'] == 'year') {
    $terms[] = $sort_attrib['order']; // we need any extra order term when sorting by year since there are to date terms biblio_year and biblio_date
    $terms[] = 'asc';
  }
  $_SESSION['last_biblio_query_terms'] = $terms;

  return (array('query'      => $query,
               'query_terms' => $terms,
               'count_query' => $count_query,
               'args'        => $args,
               'sort_attrib' => $sort_attrib,
               'rss'         => $rss_info
  ));

}

/**
 * biblio_show_results takes the query results from biblio_db_search and
 * adds some controls to the page then loops through the results applying
 * the selected style to each entry
 *
 * @param $result
 * @param $count
 * @param $attrib
 * @param $args
 * @param $inline
 * @return unknown_type
 */
function biblio_show_results($nodes, $query_info, $inline=false) {
  global $pager_total_items;
  $profile = false;
  $attrib = $query_info['sort_attrib'];
  $args   = $query_info['args'];
  $base =  variable_get('biblio_base', 'biblio');
  $style = biblio_get_style();
  if ($inline === 'profile') {
    $profile = true;
    $inline  = false;
  }
  if (module_exists('popups')){
     popups_add_popups();
  }
  if (!$inline && !$profile) {

    if (variable_get('biblio_rss', 0)) {
      drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="'.variable_get('site_name', 'Drupal').' RSS" href="'.url("$base/rss.xml").'" />');
    }
    // Search box. Has same permissions as the filter tab.
    $content = '<div id="biblio-header" class="clear-block">';
    if (variable_get('biblio_search',0) && user_access('show filter tab')) {
      $content .= drupal_get_form('biblio_search_form');
    }
    if ( biblio_access('export')) {
      $content .= '<div class="biblio-export">'. theme('biblio_export_links'). '</div>';
    }else{
      $content .= '<div class="biblio-export">'.t('Found @count results', array('@count' => $pager_total_items[0])) .'</div><br />';
    }
    // Add some links to the top of the page to change the sorting/ordering...
    if (user_access('show sort links')) {
      $content .= _biblio_sort_tabs($attrib);
    }
    $content .= '</div>';

    if  (user_access('show filter tab')) {
      $content .=  $query_info['filter_line'];
    }
  }

  if ($inline === true) print '<div class="biblio-inline">';

  if ($_GET['sort'] == 'title' ||
      $_GET['sort'] == 'author' ||
      $_GET['sort'] == 'keyword') {
    if (strpos($_GET['q'],'ag') ||
        strpos($_GET['q'],'tg') ||
        strpos($_GET['q'],'keyword')) {
      $value = substr($_GET['q'],strrpos($_GET['q'],'/')+1);
    }
    $content .= theme('biblio_alpha_line', $_GET['sort'], $value);
  }

  $count = 0;

  // Reset separator bar status for repeated calls to biblio_db_search.
  _biblio_category_separator_bar(NULL, NULL, TRUE);

  foreach ($nodes as $node) {
    $count++;
    if (is_array($node)) $node = (object)$node;
    if (variable_get('biblio_hide_bibtex_braces', 0)) $node->title = biblio_remove_brace($node->title);
    if (variable_get('biblio_fix_isi_links', 0)) biblio_fix_isi_links($node);


    // output separator bar if needed
    $content .= _biblio_category_separator_bar($attrib, $node);

    $inline_links = ($inline && variable_get('biblio_inlinemode_in_links',0)) ? true : false;

    $content .= theme('biblio_entry', $node,$base,$style,$inline_links);
  } //end while
  if ($count) $content .= '</div><!-- end category-section -->';
  $content .= theme('pager', 0, variable_get('biblio_rowsperpage', 25));
  if ($count == 0) {
    $content .= "<h3>".t("No items found")."</h3>";
    if (strstr($content, "Filters:")) {
      $content .= t('!modify_link or !remove_link your filters and try again.', array('!modify_link' => l(t('Modify'),"$base/filter"), '!remove_link' => l(t('remove'),"$base/filter/clear")));
    }
  }
  if ($profile === true)  return $content;
  if ($inline === true)   return $content . "</div>";
  if ($inline === false)  {
    drupal_set_title(check_plain(variable_get('biblio_base_title', 'Biblio')));
    return $content;
  }

}

function _biblio_sort_tabs($attrib, $options = NULL) {
  global $base_path;
  $content = '';
  $sort_links = array();
  $tabs = variable_get('biblio_sort_tabs_style', 0);
  $order = ($attrib['order'] == "desc" || $attrib['order'] == "DESC")?"asc":"desc";
  $cur_order = ($attrib['order'] == "desc" || $attrib['order'] == "DESC")?"desc":"asc";
  $path = drupal_get_path('module','biblio');
  $order_arrow = ($order == 'asc') ? ' <img src ="'. $base_path . $path. '/misc/arrow-asc.png" alt =" (Desc)" />':' <img src ="'. $base_path . $path .'/misc/arrow-desc.png" alt = " (Asc)" />';
  $sort_links =  variable_get('biblio_sort_tabs', array('author'=>'author', 'title'=>'title', 'type'=>'type', 'year'=>'year', 'keyword'=>'keyword'));
  ksort($sort_links);
  $content .= $tabs ? '<ul class="tabs secondary ">':'';

  foreach($sort_links as $key => $title) {
    $tab['path'] = $_GET['q'];
    $tab['attributes'] = array("title"=>t("Click a second time to reverse the sort order"));
    $tab['html'] = TRUE;
    $tab['text'] = t(ucfirst($title));
    if ($key === $title && $title == $attrib['sort']) {
      $tab['query'] = array('sort' => $title, 'order' => $order);
      $tab['attributes'] +=  array('class' => "active");
      $tab['active'] = TRUE;
      $tab['pfx'] = ' [ ';
      $tab['sfx'] = '] ';
      $tab['arrow'] = $order_arrow;
      $content .= _biblio_sort_tab($tab, $tabs);

    }
    elseif ($key === $title ) {
      $tab['query'] = array('sort' => $title, 'order' => $order);
      $tab['active'] = FALSE;
      $tab['pfx'] = ' ';
      $tab['sfx'] = ' ';
      $tab['arrow'] = '';
      $content .= _biblio_sort_tab($tab, $tabs);
    }

  }
  if (!$tabs) $content = t('Sort by').': '.$content;
  $content .= $tabs ? '</ul>':'';

  return $content;
}

function _biblio_sort_tab($tab, $tabs = FALSE) {
  if ($tabs) {
    $text  = '<span class="a"><span class="b">'.$tab['text'].$tab['arrow'].'</span></span>';
    $class = ($tab['attributes']['class']) ? 'class="active"' : '';
    $link  = l($text, $tab['path'], $tab);
    return "<li $class >" . str_replace('class="active"', $class, $link) . '</li>';
  }
  else {
    return $tab['pfx']. l($tab['text'], $tab['path'], $tab) . $tab['arrow'] . $tab['sfx'];
  }
  return;
}

function _biblio_filter_info_line($args) {
  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
  $content = '';
  $filtercontent = '';
  $search_content = '';
  $base =  variable_get('biblio_base', 'biblio');
  $session = &$_SESSION['biblio_filter'];
  // if there are any filters in place, print them at the top of the list
  if (count($args)) {
    $i = 0;
    while ($args) {
      $type = $args[0];
      array_shift($args);
      $value = db_escape_string($args[0]);
      if ($type == 'search') {
        $search_content = array_shift($args);
        continue;
      }
      if ($type == 'term_id') {
        $term = taxonomy_get_term($value);
        $value = $term->name;
        $type = t("Taxonomy term");
      }
      if ($type == 'keyword') {
        module_load_include('inc', 'biblio', 'includes/biblio.keywords');
        $type = t("Keyword");
        if (is_numeric($value)) {
          $term = biblio_get_keyword_by_id($value);
          $value = $term->word;
        }
        elseif (is_string($value) && strlen($value) == 1) {
          $type = t("First letter of keyword ");
        }

      }
      if ($type == 'uid' ) {
        $user = user_load($value);
        $value = $user->name;
        $type = t("Drupal user");
      }
      if ($type == 'aid' || ($type == 'author' && is_numeric($value))) {
        $author = biblio_get_contributor($value);
        $value = $author->name;
        $type = t("Author");
      }
      if ($type == 'ag' ) {
        //return;
        $type = t("First letter of last name");
      }
      if ($type == 'tg' ) {
        //return;
        $type = t("First letter of title");
      }
      if ($type == 'type' && $value > 0) {
        if (($pub_type = db_fetch_object(db_query('SELECT t.* FROM {biblio_types} as t WHERE t.tid=%d', $value)))) {
          $value = drupal_ucfirst(_biblio_localize_type($pub_type->tid, $pub_type->name));
          $type = t("Type");
        }
      }
      array_shift($args);
      $params = array('%a' =>  check_plain(ucwords($type)) , '%b' =>  check_plain($value) );
      $filtercontent .= ($i++ ? t('<em> and</em> <strong>%a</strong> is <strong>%b</strong>', $params) : t('<strong>%a</strong> is <strong>%b</strong>', $params)) ;
    }
    if ($search_content) {
      $content .= '<div class="biblio-current-filters"><b>'.t('Search results for ').'</b>';
      $content .= '<em>'. check_plain($search_content) .'</em>';
      if ($filtercontent) {
        $content .= '<br><b>'.t('Filters').': </b>';
      }
    }
    else {
      $content .= '<div class="biblio-current-filters"><b>'.t('Filters').': </b>';
    }
    $content .= $filtercontent;

    $link_options = array();
    if (isset($_GET['sort'])) {
      $link_options['query']  .= "sort=" . $_GET['sort'];
    }
    if (isset($_GET['order'])) {
      $link_options['query']   .= $link_options['query'] ? "&" : "" ;
      $link_options['query']   .= "order=" . $_GET['order'];
    }

    if ($search_content) {
      $content .= '&nbsp;&nbsp;'.l('['.t('Reset Search').']',"$base/filter/clear", $link_options);
    } else {
      $content .= '&nbsp;&nbsp;'.l('['.t('Clear All Filters').']',"$base/filter/clear", $link_options);
    }
    $content .= '</div>';
  }

  return $content;
}

function _biblio_category_separator_bar($attrib, $node, $reset = FALSE) {
  static $_text = '';
  if ($reset) { $_text = ''; return;}
  $content = '';

  switch ($attrib['sort']) {
    case 'title':
      $title = $node->biblio_sort_title;
      $first = drupal_substr(drupal_ucfirst(ltrim($title)), 0, 1);
      if ( $first  != $_text) {
        if ($_text != '' ) {
          $content .= theme_biblio_end_category_section();
        }
        $_text =  $first ;
        $content .= theme_biblio_separator_bar($_text);
      }
      break;
    case 'author':
      if ( (isset($node->biblio_contributors[1][0]['lastname'])) &&
      (drupal_substr(drupal_ucfirst(ltrim($node->biblio_contributors[1][0]['lastname'])), 0, 1) != $_text))
      {
        if ($_text != '' ) {
          $content .= theme_biblio_end_category_section();
        }
        $_text = drupal_substr(drupal_ucfirst(ltrim($node->biblio_contributors[1][0]['lastname'])), 0, 1) ;
        $content .= theme_biblio_separator_bar($_text);
      }
      break;
    case 'type':
      if ($node->biblio_type_name != $_text) {
        if ($_text != '' ) {
          $content .= theme_biblio_end_category_section();
        }
        $_text = $node->biblio_type_name;
        //      $name = db_result(db_query("SELECT name FROM {biblio_types} as t where t.tid=%d", $node->biblio_type)) ;
        $content .= theme_biblio_separator_bar(_biblio_localize_type($node->biblio_type, $_text));
      }
      break;
    case 'keyword':   // added msh 08 aug 07
      // $kw = array_shift($node->biblio_keyword);
      $tok = $node->biblio_keyword;
      if (empty($tok)) {
        $tok = t("No Keywords");
      }
      if ($tok != $_text) {
        if ($_text != '' ) {
          $content .= theme_biblio_end_category_section();
        }
        $_text = $tok;
        if ($_text != '') {
          $content .= theme_biblio_separator_bar($_text);
        }
      }
      break;
    case 'year':
    default:
      if ($node->biblio_year != $_text) {
        if ($_text != '' ) {
          $content .= theme_biblio_end_category_section();
        }
        $_text = $node->biblio_year;
        $content .= theme_biblio_separator_bar($_text);
      }
  } //end switch
  return $content;
}
function theme_biblio_separator_bar($text) {
  $content = "\n".'<div class="biblio-separator-bar">' . check_plain($text) . "</div>\n";
  $content .= "\n".'<div class ="biblio-category-section">';
  return $content;
}

function theme_biblio_end_category_section() {
  return "\n</div><!-- end category-section -->";
}

/**
 * Add a search field on the main biblio page.
 */
/**
 * @param $form_state
 * @return unknown_type
 */
function biblio_search_form(&$form_state) {
  $form['biblio_search'] = array(
    '#prefix' => '<div class="container-inline biblio-search clear-block">',
    '#suffix' => '</div>',
    );
  $form['biblio_search']['keys'] = array(
  '#type' => 'textfield',
    '#title' => '',
    '#default_value' => '',
    '#size' => 25,
    '#maxlength' => 255,
  );
  $button_text = variable_get('biblio_search_button_text', 'Biblio search');
  $form['biblio_search']['submit'] = array('#type' => 'submit', '#value' => t($button_text));
  return $form;
}

/**
 * Build the query following the do_search algorithm in search.module.
 * Unfortunately we cannot reuse anything from do_search as everything
 * is hard-coded :-(
 * @param $keys
 */
function biblio_build_search_query($keys = '') {
  if ($keys != '')  {
    $query = search_parse_query($keys);
    if ($query[2] == '') {
      form_set_error('keys', t('You must include at least one positive keyword with @count characters or more.', array('@count' => variable_get('minimum_word_size', 3))));
      return FALSE;
    }
    if ($query === NULL || $query[0] == '') return FALSE;

    $where = '('.$query[2].')';
    $args = $query[3];
    if (!$query[5]) {
      $where .= " AND ($query[0])";
      $args = array_merge($args, $query[1]);
      $join = " INNER JOIN {search_dataset} d ON i.sid = d.sid AND i.type = d.type";
    }
    // The COUNT ensures that we get only nodes where "term1 AND term2"
    // match as we demand 2 matches. Note that this doesn't work when
    // using the partial word search patch.
    $args[] =$query[4];

    $query = "SELECT distinct(i.sid) FROM {search_index} i
              INNER JOIN {node} n ON n.nid = i.sid
              $join
              WHERE n.status = 1 AND (n.type = 'biblio')
              AND $where
              AND i.type = 'node'
              GROUP BY i.type, i.sid HAVING COUNT(*) >= %d";
    return db_query(db_rewrite_sql($query), $args);
  }
  return FALSE;
}


/**
 * When we submit a search, we revoke all current filters since search
 * and filtering are considered two different concepts things* conceptually.
 *
 * But we store the results as a filter (which is just a list of node ids that
 * matched the search request) so that we can reorder or export the search
 * results like with any other filter.  The filter has three components:
 * ('search',<list of node ids>,<search keywords>).
 * The second component, the filter value, is empty when submitting keywords.
 * In biblio_db_search we fill the second component with the list of nids
 * matching our keywords, as returned by node_search.  We store the keywords
 * only for showing them in "Search results for <keywords>".
 */
/**
 * @param $form
 * @param $form_state
 * @return unknown_type
 */
function biblio_search_form_submit($form, &$form_state) {
  $keys = $form_state['values']['keys'];
  if ($keys != '')  {
    $_SESSION['biblio_filter'] = array(array('search','',$keys));
    $base =  variable_get('biblio_base', 'biblio');
    $form_state['redirect'] = $base;
  }
  else {
    // No keywords. Remove former search keys if any. Leaves other filters intact.
    if (_get_biblio_search_filter()){
      $_SESSION['biblio_filter'] = array();
    }
  }
}

/**
 * @param $arg
 * @return unknown_type
 */
function _get_biblio_search_filter($arg = 'keys') {
  if (variable_get('biblio_search',0) &&
    is_array($_SESSION['biblio_filter']) &&
    is_array($_SESSION['biblio_filter'][0]) &&
    in_array('search',$_SESSION['biblio_filter'][0])
  ){
    switch ($arg) {
      case 'keys': return $_SESSION['biblio_filter'][0][2]; break;
      case 'nodelist': return $_SESSION['biblio_filter'][0][1]; break;
    }
  }
}


function _get_biblio_filters() {

  $pub_authors[0] = '';
  $pub_years[-1] = '';
  $pub_type[0] = '';
  $pub_taxo[0] = '';
  $pub_keywords[0] = '';
  $fields = " b.biblio_year, t.name , t.tid ";
  $order = " b.biblio_year DESC";
  $taxo_fields = "td.name as termname,td.tid as taxid, v.name as vocab_name";
  $taxo_order = "vocab_name ASC, termname ASC";
  $table = "{node} as n  inner join {biblio} as b on n.vid=b.vid ";
  $join = "left join {biblio_types} as t on b.biblio_type = t.tid";
  $taxo_join = array("inner join {term_node} as tn on n.vid = tn.vid",
                     "left join  {term_data} as td on tn.tid= td.tid",
                     "left join  {vocabulary} as v on v.vid= td.vid");

  $taxo_joins = implode(' ',$taxo_join);

  $result = db_query("SELECT $fields FROM $table $join ORDER BY $order");
  $authors = db_query("SELECT firstname, initials, lastname, cid FROM {biblio_contributor_data} ORDER BY lastname ASC");
  $keywords = db_query("SELECT word, kid FROM {biblio_keyword_data} ORDER BY word ASC");
  $taxoresult = db_query("SELECT $taxo_fields FROM $table $taxo_joins ORDER BY $taxo_order");

  while ($option = db_fetch_object($result)) {
    if (isset ($option->biblio_year)) {
      $option->biblio_year = _biblio_text_year($option->biblio_year);
    }
    $pub_years["$option->biblio_year"] = $option->biblio_year;
    $pub_type["$option->tid"] = _biblio_localize_type($option->tid, $option->name);
  }

  while($auth = db_fetch_object($authors)) {
    $pub_authors[$auth->cid] = $auth->lastname .((!empty($auth->firstname) || !empty($auth->initials))?', '.$auth->firstname.' '.$auth->initials :'');
  }
  while($keyword = db_fetch_object($keywords)) {
    $pub_keywords[$keyword->kid] = $keyword->word;
  }
  while ($tax = db_fetch_object($taxoresult)) {
    $pub_taxo["$tax->taxid"] = "$tax->vocab_name - $tax->termname";
  }

  $author_select = count($pub_authors) > 1 ? array('title' => t('Author'), 'options' => $pub_authors) : null;
  $years_select  = count($pub_years) > 1   ? array('title' => t('Year'), 'options' => array_unique($pub_years)) : null;
  $type_select   = count($pub_type) > 1    ? array('title' => t('Type'), 'options' => array_unique($pub_type))  : null;
  $tax_select    = count($pub_taxo) > 1    ? array('title' => t('Term'),'options' => array_unique($pub_taxo))  : null;
  $keyword_select = count($pub_keywords) > 1 ? array('title' => t('Keyword'), 'options' => $pub_keywords) : null;

  $filters = array(
    'author'     => $author_select,
    'type'    => $type_select,
    'term_id' => $tax_select,
    'year'    => $years_select,
    'keyword'     => $keyword_select,
  );

  return $filters;
}

/**
 * @return unknown_type
 */
function biblio_form_filter() {
  // No longer use &$_SESSION so that we can alter $session in case of the search filter.
  $session = $_SESSION['biblio_filter'];
  $session = is_array($session) ? $session : array();
  $filters = _get_biblio_filters();

  $i = 0;
  $form['filters'] = array('#type' => 'fieldset',
    '#title' => t('Show only items where'),
    '#theme' => 'biblio_filters',
  );
  foreach ($session as $filter) {
    list($type, $value) = $filter;
    // Don't show the search filter. Reset $session because of the $count(session) below.
    if ($type == 'search') {
      $session = array ();
      break;
    }
    if ($type == 'category') {
      // Load term name from DB rather than search and parse options array.
      $value = module_invoke('taxonomy', 'get_term', $value);
      $value = $value->name;
    }else {
      $value = $filters[$type]['options'][$value];
    }
    $string = ($i++ ? '<em>and</em> where <strong>%a</strong> is <strong>%b</strong>' : '<strong>%a</strong> is <strong>%b</strong>');
    $form['filters']['current'][] = array('#value' => t($string, array('%a' => $filters[$type]['title'] , '%b' => $value)));
  }

  foreach ($filters as $key => $filter) {
    if (isset($filter) && count($filter['options'])) {
      $names[$key] = check_plain($filter['title']);
      $form['filters']['status'][$key] = array('#type' => 'select', '#options' => $filter['options']);
    }
  }

  $form['filters']['filter'] = array('#type' => 'radios', '#options' => $names, '#default_value' => 'author');
  $form['filters']['buttons']['submit'] = array('#type' => 'submit', '#value' => (count($session) ? t('Refine') : t('Filter')));
  if (count($session) && $type != 'search') {
    $form['filters']['buttons']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
    $form['filters']['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
  }

  return  $form;
}

/**
 * @param $form
 * @param $form_state
 * @return unknown_type
 */
function biblio_form_filter_submit($form, &$form_state) {
  // If the search filter was set, remove it now.
  if(_get_biblio_search_filter()){
    $_SESSION['biblio_filter'] = array ();
  }
  $op = $form_state['values']['op'];
  $filters = _get_biblio_filters();
  switch ($op) {
    case t('Filter'):
    case t('Refine'):
      if (isset($form_state['values']['filter'])) {
        $filter = $form_state['values']['filter'];

        // Flatten the options array to accommodate hierarchical/nested options.
        if (isset($filters[$filter]['options'])) {
          $flat_options = form_options_flatten($filters[$filter]['options']);
        }

        if (isset($flat_options[$form_state['values'][$filter]]) ) {
          $_SESSION['biblio_filter'][] = array($filter, $form_state['values'][$filter]);
          $base =  variable_get('biblio_base', 'biblio');
          drupal_goto($base);

        }
      }
      break;
    case t('Undo'):
      array_pop($_SESSION['biblio_filter']);
      break;
    case t('Reset'):
      $_SESSION['biblio_filter'] = array();
      break;
  }
}

/**
 * @param $user
 * @param $profile
 * @return unknown_type
 */
function biblio_get_user_pubs($user, $profile='', $nofilters=''){
  if (isset($user->biblio_contributor_id) && !empty($user->biblio_contributor_id) ){
    $pubs = biblio_db_search('author', $user->biblio_contributor_id, $profile, $nofilters);
  }
  elseif (isset($user->biblio_lastname) && !empty($user->biblio_lastname)) {
    $pubs = biblio_db_search('author', $user->biblio_lastname, $profile, $nofilters);
  }
  else{
    $pubs = biblio_db_search('uid', $user->uid, $profile, $nofilters);
  }

  return $pubs;
}

/**
 * @param $node
 * @return unknown_type
 */
function biblio_view_inline(&$node) {
  $style = biblio_get_style();
  $base =  variable_get('biblio_base', 'biblio');
  $layout = variable_get('biblio_node_layout', 'tabular');
  $theme = ($layout == 'tabular') ? 'biblio_tabular' : 'biblio_long';
  $output  = '<div class="biblio-inline">';
  $output .= theme($theme, $node, $base, $style);
  $output .= '</div>';
  return $output;
}

/**
 * @return unknown_type
 */
function biblio_citekey_view() {
  $citekey = arg(2);
  $nid = db_fetch_object(db_query("SELECT nid FROM {biblio} WHERE biblio_citekey = '%s' ORDER BY vid DESC", $citekey));
  if ($nid->nid > 0) {
    $node = node_load($nid->nid);
    return node_page_view($node);
  } else {
    return t("Sorry, citekey @cite not found", array('@cite'=>$citekey));
  }

}

/**
 * @param $keywords
 * @param $base
 * @return unknown_type
 */
function _biblio_keyword_links($keywords,$base='biblio') {
  $options = array();
  if (isset($_GET['sort'])) {
    $options['query']  .= "sort=" . $_GET['sort'];
  }
  if (isset($_GET['order'])) {
    $options['query']  .= $options['query'] ? "&" : "";
    $options['query']  .= "order=" . $_GET['order'];
  }
  $html = "";
  if (!is_array($keywords)) {
    module_load_include('inc', 'biblio', 'includes/biblio.keywords');
    $keywords = biblio_explode_keywords($keywords);
  }

  $sep = check_plain(variable_get('biblio_keyword_sep', ','));
  foreach($keywords as $kid => $keyword ) {
    $html .= (empty($html))? "" : "$sep ";
    $html .= l(trim($keyword), "$base/keyword/$kid" , $options);
  }
  return $html;
}

function biblio_author_page($filter = NULL) {
  $path = drupal_get_path('module', 'biblio');
  drupal_add_js($path . '/misc/biblio.highlight.js');
  $authors = _biblio_get_authors($filter);
    return _biblio_format_author_page($filter, $authors);
}

function _biblio_get_authors($filter = NULL) {
  global $user;
  $where = array();
  $where_clause = '';

  $base = variable_get('biblio_base', 'biblio');
  $menu = menu_get_active_title();
  if ($menu == 'Authors') $path = $base.'/authors/';
  if ($menu == 'Biblio settings') $path = 'admin/settings/biblio/author/list/';

  if ($filter) {
    $filter = strtoupper($filter);
    $where['filter'] =  "UPPER(SUBSTRING(lastname,1,1)) = '%s' ";
    $header_ext = t(' (whose last name starts with the letter "@letter") ',array('@letter' => $filter ));
  }
  else {
    $query_ext =  NULL;
    $header_ext = NULL;
  }

  if (!biblio_access('edit_author')) {//show only published entries to everyone except admin
    $where['status'] = 'n.status = 1 ';
  }

  if (variable_get('biblio_view_only_own', 0) ) {//show only authors that belong to nodes that the user has access to
    $where[] = "n.uid = $user->uid";
  }

  if (count($where)) {
    $where_clause = 'WHERE ('. implode(') AND (', $where) .')';
  }

  $suspects = array();
  $result = db_query('SELECT lastname FROM {biblio_contributor_data} '
                      . (isset($where['filter']) ? 'WHERE '  . $where['filter'] : '') .
                      ' GROUP BY lastname HAVING COUNT(*) > 1', array(':filter' => $filter)
             );

  while ($author = db_fetch_object($result)) {
    $suspects[] = $author->lastname;
  }

  $db_result = db_query('SELECT bd.cid, bd.drupal_uid, bd.name, bd.lastname,
                              bd.firstname, bd.prefix, bd.suffix, bd.initials,
                              bd.affiliation, bd.md5, bd.literal, COUNT(*) AS cnt
                            FROM {biblio_contributor} b
                                 LEFT JOIN {biblio_contributor_data} bd ON b.cid = bd.cid
                                 INNER JOIN {node} n on n.vid = b.vid
                            '. $where_clause.'
                            GROUP BY bd.cid, bd.drupal_uid, bd.name, bd.lastname,
                                     bd.firstname, bd.prefix, bd.suffix,
                                     bd.initials, bd.affiliation, bd.md5, bd.literal
                            HAVING COUNT(*) > 0
                            ORDER BY  lastname ASC, SUBSTRING(firstname,1,1) ASC,
                            initials ASC', $filter);

  while ($author = db_fetch_array($db_result)){
    if (array_search($author['lastname'], $suspects) !== FALSE) {
      $author['#suspect'] = TRUE;
    }
    $authors[] = $author;
  }

  return $authors;
}

function _biblio_format_author_page($filter, $authors) {
  $header_ext = $checkbox = '';
  $header = array();

  if (biblio_access('edit_author')) {
    if (!empty($filter)) {
      $header_ext = ' ' . t('whose last name begins with the letter') . ': ' . $filter;
    }
    $checkbox = array(
      '#title' => t('Hightlight possible duplicates'),
      '#type'	 => 'checkbox',
      '#id'		 => 'biblio-highlight',
    );
    $checkbox = '<div class="biblio-alpha-line">' . drupal_render($checkbox) . '</div>';
    $header = array(array('data' => t('There are a total of @count authors in the database!header_ext.', array('@count' => count($authors), '!header_ext' => $header_ext)), 'align' =>'center', 'colspan' => 3));
  }

  $rows[] = array(array('data' => theme('biblio_alpha_line', 'authors', $filter) . $checkbox, 'colspan' => 3));
  if (count($authors)) {
    for ($i=0; $i < count($authors); $i+=3) {
      $rows[] = array( array('data' => _biblio_format_author($authors[$i]) ),
      array('data' => isset($authors[$i+1])?_biblio_format_author($authors[$i+1]):'' ),
      array('data' => isset($authors[$i+2])?_biblio_format_author($authors[$i+2]):'' ));
    }
  }
  //$header = array(array('data' => t('There are a total of @count authors !header_ext in the database',array('@count' => count($authors), '!header_ext' => $header_ext)), 'align' =>'center', 'colspan' => 3));
  $output = theme('table', $header, $rows);
  return $output;
}
/*
 * Helper function to format the authors and add edit links if required
 */
function _biblio_format_author($author) {
  static $author_options = array();
  $style_name = biblio_get_style();
  module_load_include('inc', 'biblio', "styles/biblio_style_$style_name");
  $inline = FALSE;
  $format = biblio_format_authors(array($author));
  $format .= ' ('. $author['cnt'] . ') '. ((biblio_access('edit_author'))?_biblio_author_edit_links($author):'');

  if (biblio_access('edit_author') && isset($author['#suspect'])) {
    $format = '<div class="suspect">' . $format . '</div>';
  }
  return $format;
}

function _biblio_author_edit_links($author) {
  static $path = '';
  if (empty($path)){
    $path =  (ord(substr($_GET['q'],-1)) > 97) ? $_GET['q'] . "/" : substr($_GET['q'], 0, -1);
    $path = (strpos($path, 'list/')) ? str_replace('list/', '', $path) : $path;
  }
  return l(' ['.t('edit').']', $path . $author['cid'] ."/edit/" );
}

function biblio_keyword_page($filter = NULL) {
  $keywords = _biblio_get_keywords($filter);
  return _biblio_format_keyword_page($filter, $keywords);
}

function _biblio_get_keywords($filter = NULL) {
  global $user;
  $where = array();
  $where_clause = '';
  if ($filter) {
    $filter = strtoupper($filter);
    $where[] =  "UPPER(SUBSTRING(word,1,1)) = '%s' ";
    $header_ext = t(' (which start with the letter "@letter") ',array('@letter' => $filter ));
  }
  else {
    $query_ext =  NULL;
    $header_ext = NULL;
  }

  if ($user->uid != 1 ) {//show only published entries to everyone except admin
    $where[] = 'n.status = 1 ';
  }

  if (variable_get('biblio_view_only_own', 0) ) {//show only authors that belong to nodes that the user has access to
    $where[] = "n.uid = $user->uid";
  }
  if (count($where)) {
    $where_clause = count($where) > 1 ? 'WHERE ('. implode(') AND (', $where) .')': 'WHERE '. $where[0];
  }

  $db_result = db_query('SELECT bkd.kid, bkd.word, COUNT(*) AS cnt
                         FROM {biblio_keyword} bk
                         LEFT JOIN {biblio_keyword_data} bkd ON bkd.kid = bk.kid
                         LEFT JOIN {node} n ON n.vid = bk.vid
                         '. $where_clause. '
                         GROUP BY bkd.kid, bkd.word HAVING COUNT(*) > 0
                         ORDER BY  word ASC', $filter);

  while ($keyword = db_fetch_object($db_result)){
    $keywords[] = $keyword;
  }
  return $keywords;
}

function _biblio_format_keyword_page($filter, $keywords) {
  $rows[] = array(array('data' => theme('biblio_alpha_line', 'keywords', $filter), 'colspan' => 3));
  for ($i=0; $i < count($keywords); $i+=3) {
    $rows[] = array( array('data' => _biblio_format_keyword($keywords[$i]) ),
    array('data' => isset($keywords[$i+1])?_biblio_format_keyword($keywords[$i+1]):'' ),
    array('data' => isset($keywords[$i+2])?_biblio_format_keyword($keywords[$i+2]):'' ));
  }
  //$header = array(array('data' => t('There are a total of @count keywords !header_ext in the database',array('@count' => count($keywords), '!header_ext' => $header_ext)), 'align' =>'center', 'colspan' => 3));
  $output .= theme('table', $header, $rows);
  return $output;
}
function _biblio_format_keyword($keyword) {
  $base      = variable_get('biblio_base', 'biblio');
  $format    = l(trim($keyword->word), "$base/keyword/$keyword->kid" );
  $format   .= ' ('. $keyword->cnt . ') ' ;
  $path =  (ord(substr($_GET['q'],-1)) > 97) ? $_GET['q'] . "/" : substr($_GET['q'], 0, -1);
  $edit_link = ' ['.l(t('edit'), $path . $keyword->kid . "/edit" ).'] ';
  $format   .= (user_access('administer biblio')) ? $edit_link: '';

  return $format;
}
